package zdream.control.world;

import java.util.*;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;

import zdream.utils.function.VoidFunction;

/**
 * @author Zdream
 * @date 2023-11-23
 * @since 0.0.1
 */
public class MHookStore {
	protected final Map<MHookType, List<HookHandler>> handlers = new HashMap<>();
	public int id = 0;

	public BooleanSupplier registerHook(MHookType hookType, HookHandler wrapper) {
		handlers.compute(hookType, ((hookType1, hookHandlers) -> {
			if (hookHandlers == null) {
				hookHandlers = new ArrayList<>();
			}
			hookHandlers.add(wrapper);
			return hookHandlers;
		}));

		return () -> Optional.ofNullable(handlers.get(hookType))
				.map(list -> list.remove(wrapper))
				.orElse(false);
	}

	public HookHandlerBuilder hookBuilder() {
		final HookHandlerBuilder builder = new HookHandlerBuilder(++id);
		builder.saveHandler = b -> registerHook(b.hookType, b.build());
		return builder;
	}

	void fill(MHooks.MHookContext context) {
		fill(context, context.hookType);
	}

	void fill(MHooks.MHookContext context, MHookType type) {
		final List<HookHandler> list = handlers.get(type);
		if (list == null) {
			return;
		}

		final List<HookHandler> copied = context.handlers;
		copied.addAll(list);
	}

	public static class HookHandler implements Comparable<HookHandler> {
		public final Consumer<MHooks.MHookContext> handler;
		public final int id;
		public final int priority;

		private HookHandler(Consumer<MHooks.MHookContext> handler, int id, int priority) {
			this.handler = Objects.requireNonNull(handler);
			this.id = id;
			this.priority = priority;
		}

		@Override
		public int compareTo(HookHandler o) {
			if (this.priority == o.priority) {
				return this.id - o.id;
			}
			return this.priority - o.priority;
		}

		@Override
		public String toString() {
			return handler.toString();
		}
	}

	public static class HookHandlerBuilder {
		public final int id;
		private Consumer<MHooks.MHookContext> handler;
		private MHookType hookType;
		private int priority;
		private Function<HookHandlerBuilder, BooleanSupplier> saveHandler;
		private Consumer<BooleanSupplier> cleaner;

		public HookHandlerBuilder(int id) {
			this.id = id;
		}

		public HookHandlerBuilder handle(Consumer<MHooks.MHookContext> handler) {
			this.handler = handler;
			return this;
		}

		public HookHandlerBuilder handle(VoidFunction handler) {
			this.handler = (ignored) -> handler.run();
			return this;
		}

		public HookHandlerBuilder withType(MHookType hookType) {
			this.hookType = hookType;
			return this;
		}

		/**
		 * 优先级, 低的优先执行. 默认 0.
		 * 测 buff 执行的先后顺序交给 case.
		 */
		public HookHandlerBuilder withPriority(int priority) {
			this.priority = priority;
			return this;
		}

		public HookHandlerBuilder withCleaner(Consumer<BooleanSupplier> cleaner) {
			Objects.requireNonNull(cleaner);
			this.cleaner = (this.cleaner == null) ? cleaner : this.cleaner.andThen(cleaner);
			return this;
		}

		private HookHandler build() {
			return new HookHandler(this.handler, id, priority);
		}

		public BooleanSupplier buildAndSave() {
			final BooleanSupplier cleaner = this.saveHandler.apply(this);
			if (this.cleaner != null) {
				this.cleaner.accept(cleaner);
			}
			return cleaner;
		}
	}
}
